<template>
    <div>
      <div class="app-container">
        <div class="product-manual">
          <div class="flex flex-j-between">
            <el-upload
              action=""
              :auto-upload="false"
              :show-file-list="false"
              :on-change="handleFileUpload"
              accept=".xlsx,.xls"
            >
              <template #trigger>
                <el-button type="primary" style="margin-right: 10px;">
                  上传 Excel
                </el-button>
              </template>
  
              <el-button
                type="success"
                @click="download"
                plain
              >
                导出pdf
              </el-button>
            </el-upload>
  
            <div class="flex flex-vc">
              <a class="mr10 color-theme pdf-model-link" :href="choiceModel.link">
                {{ choiceModel.label }}下载
              </a>
              <el-select
                v-model.number="pdfModelValue"
                placeholder="请选择模板类型"
                style="width: 200px;"
              >
                <el-option
                  v-for="item in pdfOptions"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                />
              </el-select>
            </div>
          </div>
  
          <div class="flex flex-vc">
            <div class="pdf-label">
              pdf名称：
            </div>
            <el-input
              class="pdf-name"
              v-model="pdfName"
              placeholder="请输入pdf名称"
            />
          </div>
          <!-- 渲染 Excel 生成的 HTML 表格 -->
          <div id="output" v-html="tableHtml" />
        </div>
      </div>
    </div>
  </template>
  
  <script>
    import * as ExcelJS from 'exceljs';
    import {
      sheetCustomStyles,
      themeColors,
      pdfOptions,
      imgTitleUrl
    } from './pdf-config/config';
    import { Loading } from 'element-ui';
  
    export default {
      name: 'ProductManual',
      data() {
        return {
          worksheetIds: [], // 存储所有工作表的ID
          pdfModelValue: 1,
          pdfName: '',
          tableHtml: '',
          pdfOptions, // pdf模板下拉列表
          sheetCustomStyles, // 模板样式
          themeColors, //excel主题色
          imgTitleUrl, // 标题图片
          sheetCommonStyle: 'padding:20px 14px 0;',
          sheetSpecialStyle: 'background: #fff;padding:26px 0 20px;border-radius: 16px;margin-bottom: 40px;box-shadow: 0px 6px 16px 0px rgba(132,220,214,0.52);',
          imgTitleNumber: 0, // 标题图片位置
          imgTitleUrlLength: Object.keys(imgTitleUrl).length
        };
      },
      computed: {
        choiceModel() {
          return this.pdfOptions.find(v => v.value === this.pdfModelValue);
        }
      },
      methods: {
        // 读取 Excel 并转换成 HTML
        async readExcel(file) {
          const that = this;
          const workbook = new ExcelJS.Workbook();
          const arrayBuffer = await file.arrayBuffer();
          const { worksheets } = await workbook.xlsx.load(arrayBuffer);
          this.worksheetIds = worksheets.map(v => v.id);
          let allHtml = '';
          this.imgTitleNumber = 0;
          allHtml += `<div style="${
            this.sheetCustomStyles['template' + [this.pdfModelValue]][
              'homePageStyle'
            ]
          }">`;
          allHtml += `<div style="${
            this.sheetCustomStyles['template' + [this.pdfModelValue]]['titleStyle']
          }">${this.pdfName}</div>`;
          workbook.eachSheet(function (worksheet, sheetId) {
            allHtml += that.handleSheetData(worksheet, sheetId)
          });
          allHtml += '<div style="margin-bottom: 20px;font-size: 16px;color: #29B1C9;text-align: center;font-weight: 600;">*本产品介绍仅可用作保险保障指南，具体的承保范围以实际订立的保险合同规定为准。</div>';
          allHtml += '</div>';
          return allHtml;
        },
        // 处理excel表格数据
        handleSheetData(worksheet, sheetId) {
          try {
            const currentSheetIndex = this.worksheetIds.indexOf(sheetId);
            const isShowTitleImg = worksheet.name.includes('+'); // 与运营同学约定sheet带有-符号则显示大标题
            let html = '';
    
            if (isShowTitleImg) {
              // 含有大标题
              if (currentSheetIndex > 0) {
                html += '</div>';
              }
              html += `<div class="sheet-wrap" style="${this.sheetSpecialStyle}${currentSheetIndex === 0 ? 'padding:16px 14px;' : ''}${this.imgTitleUrlLength - 1 === this.imgTitleNumber ? 'margin-bottom: 20px;' : ''}">`;
            }
            html += `<div class="sheet" style="${currentSheetIndex > 0 ? this.sheetCommonStyle : ''}">`;
            html += `<div class="table-box" style="position: relative;${currentSheetIndex === 0 ? 'background: rgba(230, 246, 251, 0.6);padding:14px 18px;border-radius: 12px;' : ''}">`;
            if (isShowTitleImg) {
              const signStyle = `width: 284px;height: 44px;position: absolute;top: ${currentSheetIndex === 0 ? '-33px' : '-63px'};left:50%;transform: translateX(-50%);background: url(${this.imgTitleUrl[this.imgTitleNumber]}) no-repeat;background-size: 100%,100%;`;
              html += `<div class="table-sign" style="${signStyle}"></div>`;
              this.imgTitleNumber++;
            }
            html += '<table cellpadding="5" style="border-collapse: collapse;width: 100%;">';
            // 获取合并单元格信息
            const merges = this.getAllMergeRanges(worksheet);
            // 处理合并单元格映射
            const mergeMap = {};
            merges.forEach(merge => {
              // 解析合并范围
              const { top, left, bottom, right } = this.parseMergeRange(merge);
              mergeMap[`${top}:${left}`] = {
                rowSpan: bottom - top + 1,
                colSpan: right - left + 1
              };
              // 标记合并区域内的所有单元格
              for (let r = top; r <= bottom; r++) {
                for (let c = left; c <= right; c++) {
                  if (r !== top || c !== left) {
                    mergeMap[`${r}:${c}`] = { isMerged: true };
                  }
                }
              }
            });
            // 获取行和列范围
            const dimensions = worksheet.dimensions.model;
            const minRow = dimensions ? dimensions.top : 1;
            const maxRow = dimensions ? dimensions.bottom : worksheet.rowCount;
            const minCol = dimensions ? dimensions.left : 1;
            const maxCol = dimensions ? dimensions.right : (worksheet.getRow(minRow).cellCount || 0);
            // 遍历行
            for (let rowNumber = minRow; rowNumber <= maxRow; rowNumber++) {
              const row = worksheet.getRow(rowNumber);
              if (!row) continue;
              html += '<tr>';
              // 遍历列
              for (let colNumber = minCol; colNumber <= maxCol; colNumber++) {
                const cell = row.getCell(colNumber);
                const mergeKey = `${rowNumber}:${colNumber}`;
                const mergeInfo = mergeMap[mergeKey];
                  
                // 跳过合并单元格的非起始位置
                if (mergeInfo && mergeInfo.isMerged) {
                  continue;
                }
                // 开始单元格
                let cellHtml = '<td';
                // 添加合并属性
                if (mergeInfo && (mergeInfo.rowSpan || mergeInfo.colSpan)) {
                  if (mergeInfo.rowSpan > 1) {
                    cellHtml += ` rowspan="${mergeInfo.rowSpan}"`;
                  }
                  if (mergeInfo.colSpan > 1) {
                    cellHtml += ` colspan="${mergeInfo.colSpan}"`;
                  }
                }
    
                // 添加样式
                const style = this.getCellStyle(cell, !!(mergeInfo && (mergeInfo.rowSpan || mergeInfo.colSpan)));
    
                if (style) {
                  cellHtml += ` style="${style}"`;
                }
                
                cellHtml += '>';
                
                // 添加内容
                let value = cell.value;
                if (value === null || value === undefined) {
                  value = '';
                } else if (typeof value === 'object') {
                  // 处理富文本
                  if (value.richText) {
                    value = value.richText.map(rt => {
                      let text = rt.text;
                      text = this.replaceNewlines(text);
                      if (rt.font) {
                        let spanStyle = '';
                        if (rt.font.bold) spanStyle += 'font-weight: bold;';
                        if (rt.font.italic) spanStyle += 'font-style: italic;';
                        if (rt.font.size) spanStyle += `font-size: ${rt.font.size}px;`;
                        if (rt.font.color) {
                          spanStyle += `color: ${this.parseColor(rt.font.color)};`;
                        }
                        if (spanStyle) {
                          text = `<span style="${spanStyle}">${text}</span>`;
                        }
                      }
                      return text;
                    }).join('');
                  } else {
                    value = value.text ? this.replaceNewlines(value.text) : '';
                  }
                } else {
                  // 处理普通文本的换行
                  value = this.replaceNewlines(value.toString());
                }
                  
                cellHtml += value;
                cellHtml += '</td>';
                
                html += cellHtml;
              }
              html += '</tr>';
            }
              
            html += '</table>';
            html += '</div>'; //sheet的闭合标签
            html += '</div>'; //shee的闭合标签
            // sheet-wrap闭合标签
            if (currentSheetIndex == this.worksheetIds.length - 1) {
              html += '</div>';
            }
            return html;
          } catch (error) {
            return '';
          }
        },
        // 设置表格单元格样式
        getCellStyle(cell, isBool) {
          const style = ['box-sizing: border-box;min-width: 50px;line-height: 17px;'];
          // 背景色
          if (cell.fill && cell.fill.fgColor) {
            style.push(`background-color: ${this.parseColor(cell.fill.fgColor)}`);
          }
          // 字体颜色
          if (cell.font && cell.font.color) {
            style.push(`color: ${this.parseColor(cell.font.color)}`);
          }
          // 字体加粗
          if (cell.font && cell.font.bold) {
            style.push('font-weight: bold');
          }
          // 字体倾斜
          if (cell.font && cell.font.italic) {
            style.push('font-style: italic');
          }
          // 字体大小
          if (cell.font && cell.font.size) {
            style.push(`font-size: ${cell.font.size}px`);
          }
          // 对齐方式
          if (cell.alignment) {
            if (cell.alignment.horizontal) {
              style.push(`text-align: ${cell.alignment.horizontal}`);
            }
            if (cell.alignment.vertical) {
              style.push(`vertical-align: ${cell.alignment.vertical}`);
            }
            // 处理自动换行
            if (cell.alignment.wrapText) {
              style.push('white-space: pre-wrap');
            }
          }
          // 边框
          if (cell.border) {
            const borders = [];
            const direction = ['top', 'left', 'bottom', 'right'];
            direction.forEach(side => {
              if (cell.border[side]) {
                const border = cell.border[side];
                borders.push(`border-${side}: 1px solid ${this.parseColor(border.color)}`);
              }
            });
            if (borders.length) {
              style.push(...borders);
            }
            // 特殊处理，合并单元格只有一条边框补全其他边框逻辑
            const bordersStr = borders.join('');
            if (isBool && borders.length && borders.length > 0) {
              direction.forEach(dir => {
                if (!bordersStr.includes(dir)) {
                  style.push(`border-${dir}: 1px solid ${this.parseColor()}`);
                }
              });
            }
          }
          return style.join('; ');
        },
        // 处理颜色
        parseColor(color) {
          if (!color) return '#29B1C9';
          if (color.argb) {
            const argb = color.argb;
            // 转换 ARGB 为 RGBA
            const alpha = parseInt(argb.substr(0, 2), 16) / 255;
            const red = parseInt(argb.substr(2, 2), 16);
            const green = parseInt(argb.substr(4, 2), 16);
            const blue = parseInt(argb.substr(6, 2), 16);
            return `rgba(${red}, ${green}, ${blue}, ${alpha})`;
          }
          if (color.theme !== undefined) {
            return this.themeColors[color.theme] || '#FFFFFF'; // 主题色转换
          }
          return color;
        },
        // 替换换行符为HTML换行标签
        replaceNewlines(text) {
          if (!text) return '';
          return text.toString()
            .replace(/\r\n/g, '<br>')
            .replace(/\n/g, '<br>')
            .replace(/\r/g, '<br>');
        },
        // 解析合并范围（支持A1:B2格式）
        parseMergeRange(merge) {
          // 如果是字符串格式（如"A1:B2"）
          if (typeof merge === 'string') {
            const [start, end] = merge.split(':');
            const startCol = this.letterToColumn(start.match(/[A-Z]+/)[0]);
            const startRow = parseInt(start.match(/\d+/)[0]);
            const endCol = this.letterToColumn(end.match(/[A-Z]+/)[0]);
            const endRow = parseInt(end.match(/\d+/)[0]);
            
            return {
              top: startRow,
              left: startCol,
              bottom: endRow,
              right: endCol
            };
          }
          return {};
        },
        // 将Excel列字母转换为列号（A=1, B=2, ..., Z=26, AA=27等）
        letterToColumn(letter) {
          let column = 0;
          const length = letter.length;
          for (let i = 0; i < length; i++) {
            column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
          }
          return column;
        },
        // 获取所有合并区域 - 兼容各种ExcelJS版本
        getAllMergeRanges(worksheet) {
          // 尝试各种可能的属性路径
          const possibleMergePaths = [
            () => worksheet.merges, // 新版本
            () => worksheet.model && worksheet.model.merges // 另一种可能
          ];
          
          for (const path of possibleMergePaths) {
            try {
              const merges = path();
              if (merges && merges.length > 0) {
                return merges;
              }
            } catch (e) {
              console.warn('Failed to access merge ranges:', e);
            }
          }
          
          // 如果以上方法都失败，尝试从单元格中提取合并信息
          console.warn('Using fallback method to detect merged cells');
          const merges = [];
          const dimensions = worksheet.dimensions;
          if (!dimensions) return merges;
          
          for (let r = dimensions.top; r <= dimensions.bottom; r++) {
            const row = worksheet.getRow(r);
            if (!row) continue;
            
            for (let c = dimensions.left; c <= dimensions.right; c++) {
              const cell = row.getCell(c);
              if (cell.isMerged && cell.master) {
                // 这是一个合并单元格的主单元格
                merges.push({
                  top: cell.master.row,
                  left: cell.master.col,
                  bottom: cell.master.row + cell.master.rowSpan - 1,
                  right: cell.master.col + cell.master.colSpan - 1
                });
              }
            }
          }
          
          return merges;
        },
        async handleFileUpload(file) {
          if (!this.pdfName) return this.$message.error('请输入pdf名称');
          let loadingInstance = Loading.service();
          const excelData = await this.readExcel(file.raw);
          loadingInstance && loadingInstance.close();
          this.tableHtml = excelData; // 更新 HTML 表格内容
        },
        // 下载pdf
        async download() {
          if (!this.tableHtml) return this.$message.error('请先上传excel文件');
          if (!this.pdfName) return this.$message.error('请输入pdf名称');
          let loadingInstance = Loading.service();
          const response = await fetch('https://test.wxb.com.cn/node-service-koa2/generate-pdf', {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({ html: this.tableHtml })
          });
          loadingInstance && loadingInstance.close();
          const blob = await response.blob();
          const url = window.URL.createObjectURL(blob);
          const link = document.createElement('a');
          link.href = url;
          link.download = 'document.pdf';
          document.body.appendChild(link);
          link.click();
          window.URL.revokeObjectURL(url);
          document.body.removeChild(link);
        },
      }
    };
  </script>
  
  <style lang="scss" scoped>
    .product-manual {
      padding: 20px;
      background-color: #fff;
      min-height: 85vh;
    }
  
    .pdf-label {
      font-weight: 600;
      margin-right: 10px;
    }
  
    .pdf-name {
      width: 200px;
      margin: 10px 0;
    }
  
    .pdf-model-link {
      font-size: 14px;
      cursor: pointer;
    }
  </style>
  